/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package alloytoy;

import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import tracetoautomata.DFA;
import tracetoautomata.State;

/**
 * Reads a xml representation of a alloy model and returns the correspondent DFA object.
 * @author Daniel
 */

class XMLSignature{
    String signatureName;
    Integer Id;
    ArrayList<Integer> parentId;

    public XMLSignature(){
        parentId=new ArrayList<Integer>();
    }
    
    public int CountOcorr(String orig, String substring){
        int lastIndex = 0;
        int count =0;
        while(lastIndex != -1 && lastIndex<orig.length()){
            lastIndex = orig.indexOf(substring,lastIndex);
            if( lastIndex != -1){
                count ++;
                lastIndex++;
            }
        }
        return count;
    }

    /* Connects ID20 to 14
     * <types> <type ID="20"/> <type ID="14"/> </types>
     * Connects ID29 to 28
     * <types> <type ID="29"/> <type ID="33"/> <type ID="28"/> </types>
     */
    public void XMLLineTypes(String line){
        Integer pId;
        if(CountOcorr(line, "<type ")==2){
            int pos1 = line.indexOf("ID=\"");
            int pos2 = line.indexOf("ID=\"",pos1+1);
            int pos3 = line.indexOf('"',pos2+4);
            pId = Integer.parseInt(line.substring(pos2+4, pos3));
            parentId.add(pId);
        }
        if(CountOcorr(line,"<type ")==3){
            int pos1 = line.indexOf("ID=\"");
            int pos2 = line.indexOf("ID=\"",pos1+1);
            int pos3 = line.indexOf("ID=\"",pos2+1);
            int pos4 = line.indexOf('"',pos3+4);
            pId = Integer.parseInt(line.substring(pos3+4, pos4));
            parentId.add(pId);
        }
    }
    //Extract signature name, ID and ParentId from: <sig label="this/ConselhoPedagogico" ID="25" parentID="2">
    public void XMLLineSig(String line){
        int posone = line.indexOf("this/");
        int postwo = line.indexOf('"',posone);
        signatureName = line.substring(posone+5, postwo);
        int posthree = line.indexOf("ID=\"");
        int posfour = line.indexOf('"',posthree+4);
        Id = Integer.parseInt(line.substring(posthree+4, posfour));
        int posfive = line.indexOf("parentID=\"");
        int possix = line.indexOf('"',posfive+10);
        parentId.add(Integer.parseInt(line.substring(posfive+10,possix)));
    }
}
public class XMLParser {
    String fileName;
    ArrayList<String> sigs;
    Map<String,Integer> sigsId;
    Map<Integer,ArrayList<Integer>> parentsId;
    Map<String,Integer> finalMap;

    public XMLParser(String sfileName){
        fileName = sfileName;
        sigs = new ArrayList<String>();
        sigsId = new HashMap<String,Integer>();
        parentsId = new HashMap<Integer,ArrayList<Integer>>();
    }

    //Receives: <atom label="State$0"/> and returns: State$0
    public String extractAtomName(String line){
        return line.substring(line.indexOf("label=")+7, line.length()-3);
    }

    //Receives: <field label="esq" ID="11" parentID="10"> and returns: esq
    public String extractRelName(String line){
        return line.substring(14, line.indexOf(" ID=")-1);
    }
    
    public ArrayList<String> extractNamesField(String line){
        String[] explode = line.split(" ");
        ArrayList<String> names = new ArrayList<String>();
        for(String s : explode){
            if(s.indexOf("label=")!=-1){
                String atomName = s.substring(7, s.length()-3);
                names.add(atomName);
            }
        }
       return names;
    }

    public State getStateFromList(ArrayList<State> states, String atom){
        for(State s : states){
            if(s.getAtom().equals(atom))
                return s;
        }
        return null;
    }


    public void FieldLine(String relation, String line, ArrayList<State> stateList){
        ArrayList<String> atomsNames = extractNamesField(line);
        
        State oState = getStateFromList(stateList,atomsNames.get(0));
        if(oState!=null){
            
            oState.addStates(relation, atomsNames);
            /*
            for(int i=1; i<atomsNames.size(); i++){
                State tmp = getStateFromList(stateList,atomsNames.get(i));
                if(tmp!=null){
                    oState.addState(relation, tmp);
                }
            }*/
        }
  }

  public boolean ContainsAny(String line, ArrayList<String> words){

      for(String s : words)
          if(line.indexOf(s)!=-1) return true;
      return false;
  }
  public DFA parseFileToStates(ArrayList<String> orderingSigs){
        FileInputStream fis;
        ArrayList<State> orderStates = new ArrayList<State>();
        try {
            fis = new FileInputStream(fileName);
            BufferedInputStream bis = new BufferedInputStream(fis);
            DataInputStream dis = new DataInputStream(bis);
            String line;
            line = dis.readLine();
            while(dis.available() !=0){
                
                if(line.indexOf("this/")!=-1){
                    if(ContainsAny(line,orderingSigs)){
                        line = dis.readLine();
                        while(line.indexOf("</sig>")==-1){
                            State order = new State(extractAtomName(line),true);
                            orderStates.add(order);
                            line=dis.readLine();
                        }
                    }
                    else{
                        line = dis.readLine();
                        while(line.indexOf("</sig>")==-1){
                            State order = new State(extractAtomName(line),false);
                            orderStates.add(order);
                            line=dis.readLine();
                        }

                    }
                }
                //Para todas as relações do modelo
                if(line.indexOf("<field label=")!=-1 && line.indexOf("private=\"yes\"")==-1){
                    String relName = extractRelName(line);
                    
                    line = dis.readLine();
                    while(line.indexOf("</field>")==-1){
                        if(line.indexOf("<atom ")!=-1){
                            FieldLine(relName,line,orderStates);
                        }
                        line = dis.readLine();
                    }
                }
                line = dis.readLine();
            }

            //Construct the Automaton
            ArrayList<State> autoStates = new ArrayList<State>();
            for(State s : orderStates){
                if(s.isOrderingState())
                    autoStates.add(s);
            }
            DFA auto = new DFA(autoStates);
            return auto;
            
        }
        catch (IOException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return null;
    }

    public Map<String,Integer> parseFile(){
        FileInputStream fis;
        try {
            fis = new FileInputStream(fileName);
            BufferedInputStream bis = new BufferedInputStream(fis);
            DataInputStream dis = new DataInputStream(bis);
            String line;
            line = dis.readLine();
            while(dis.available() !=0){
                if(line.indexOf("this/")!=-1){
                    XMLSignature xmlSig = new XMLSignature();
                    xmlSig.XMLLineSig(line);
                    line = dis.readLine();
                    while(line!=null && line.indexOf("this/")==-1){
                        if(line.indexOf("<types>")!=-1)
                            xmlSig.XMLLineTypes(line);
                        line=dis.readLine();
                    }
                    /*System.out.println("Nome: "+xmlSig.signatureName);
                    System.out.println("Id: "+xmlSig.Id);
                    System.out.println("ParentsIds: "+xmlSig.parentId);*/
                    sigs.add(xmlSig.signatureName);
                    sigsId.put(xmlSig.signatureName, xmlSig.Id);
                    parentsId.put(xmlSig.Id, xmlSig.parentId);
                }
                else{
                    line = dis.readLine();
                }
            }
            Digraph graph = new Digraph(sigs.size());
            String sigName;
            Integer sigId;
            ArrayList<Integer> pId;
            for(int i=0; i<sigs.size(); i++){
                sigName = sigs.get(i);
                sigId = sigsId.get((sigName));
                pId = parentsId.get(sigId);
                //System.out.println("Sig: "+sigName+"\tId="+sigId);
                for(int j=0; j<pId.size(); j++){
                    //System.out.println("Sig: "+sigName+"\tId="+sigId+"\tPId="+pId);
                    if(sigsId.containsValue(pId.get(j))){
                        String parentName = getSigName(pId.get(j));
                        graph.insert(i, sigs.indexOf(parentName));
                        //System.out.println(parentName);
                    }
                }
            }
            return DotParser.ConstructMap(graph, sigs);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (IOException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public final String getSigName(Integer Id){
        for(int i=0; i<sigs.size(); i++){
            if(sigsId.get(sigs.get(i)).equals(Id))
                return sigs.get(i);
        }
        return null;
    }
}
